package jscinttools.datafit;

import java.lang.System;

import hep.aida.*;

import fr.in2p3.ipnl.aidautilities.AidaUtil;

import jscinttools.datafit.*;
import jscinttools.datafit.scint.*;
import jscinttools.utilities.aidautilities.AidaFactories;

import jhplot.P1D;
import jhplot.H1D;

/**
 *  The Main Class for Fitting Datas
 *
 *@author     Marc-Antoine Verdier
 *@created    8 avril 2011
 */
public class DataFitter
{
	private IFitter fitter;
	private FitFunction fitFunc;
	private IFunction func;


	/**
	 *  Constructor for the DataFitter object
	 *
	 *@param  fitFunc  The FitFunction that will be used for fitting
	 */
	public DataFitter(FitFunction fitFunc)
	{
		this(fitFunc, AidaFactories.FIT_FACTORY.createFitter("Chi2", "jminuit"));
	}



	/**
	 *  Constructor for the DataFitter object
	 *
	 *@param  fitFunc  The FitFunction that will be used for fitting
	 *@param  fitter   The IFitter used for fitting (default is "Chi2", "jminuit")
	 */
	public DataFitter(FitFunction fitFunc, IFitter fitter)
	{
		this.fitFunc = fitFunc;
		this.fitter = fitter;
	}


	///**
	// *  Prepare the fit
	// *
	// *@param  fitSettings  Description of the Parameter
	// *@return              Description of the Return Value
	// */
	//private IFunction prepareFit(FitSettings fitSettings)
	//{
	//	double[] param = fitSettings.getStartParam();
	//	IFunction func = fitFunc.fitFunction(param);
	//	//IFitParameterSettings[] fitParamSet = new IFitParameterSettings[param.length];
	//	//for (int i = 0; i < param.length; i++)
	//	//{
	//	//	fitParamSet[i] = fitter.fitParameterSettings(func.parameterNames()[i]);
	//	//	fitParamSet[i].setFixed(fitSettings.isFixed(i));
	//	//	fitParamSet[i].setBounds(fitSettings.getBounds(i, 0), fitSettings.getBounds(i, 1));
	//	//}
	//	IFitParameterSettings[] fitParamSet = fitSettings.fitSettings(fitter, func);
	//	return func;
	//}

	/**
	 *  Prepare the fit
	 *
	 *@param  fitSettings  Description of the Parameter
	 *@return              Description of the Return Value
	 */
	private IFunction prepareFit(FitSettings fitSettings)
	{
		double[] param = fitSettings.getStartParam();
		boolean[] fixed = fitSettings.isFixed();
		//double[][] bounds = fitSettings.getBounds();
		double[] upperBound = fitSettings.getUpperBound();
		double[] lowerBound = fitSettings.getLowerBound();

		IFunction func = fitFunc.fitFunction(param);
		String[] paramNames = func.parameterNames();

		fitter.resetParameterSettings();
		IFitParameterSettings[] fitParamSet = new IFitParameterSettings[paramNames.length];
		for (int i = 0; i < paramNames.length; i++)
		{
			fitParamSet[i] = fitter.fitParameterSettings(paramNames[i]);
			fitParamSet[i].setFixed(fixed[i]);
			fitParamSet[i].setBounds(lowerBound[i], upperBound[i]);
		}
		return func;
	}


	//private void prepareFitter()

	//private void prepareFitter(IFunction func, FitSettings fitSettings)
	//{
	//	IFitParameterSettings[] fitParamSet = new IFitParameterSettings[func.parameterNames().length];
	//	for (int i = 0; i < func.parameterNames().length; i++)
	//	{
	//		fitParamSet[i] = fitter.fitParameterSettings(func.parameterNames()[i]);
	//		fitParamSet[i].setFixed(fixed[i]);
	//		fitParamSet[i].setBounds(bounds[i][0], bounds[i][1]);
	//	}
	//}


	/**
	 *  Fit the IDataPointSet
	 *
	 *@param  dps          The IDataPointSet to be fitted
	 *@param  fitSettings  The FitSettings to be used
	 *@return              The results of the fit
	 */
	public IFitResult doFit(IDataPointSet dps, FitSettings fitSettings)
	{
		IFunction func = prepareFit(fitSettings);
		return fitter.fit(dps, func);
	}


	/**
	 *  Fit the P1D
	 *
	 *@param  p1d          The P1D to be fitted
	 *@param  fitSettings  The FitSettings to be used
	 *@return              The results of the fit
	 */
	public IFitResult doFit(P1D p1d, FitSettings fitSettings)
	{
		IFunction func = prepareFit(fitSettings);
		IDataPointSet dps = p1d.getIDataPointSet();
		return fitter.fit(dps, func);
	}


	///**
	// *  Fit the Imanaged Object with the IFunction
	// *
	// *@param  dps          The IDataPointSet to be fitted
	// *@param  fitSettings  The FitSettings used
	// *@return              The IFitResult
	// */
	//public IFitResult doFit(IDataPointSet dps, FitSettings fitSettings)
	//{
	//	IFitResult fitResult = fitter.fit(dps, prepareFit(fitSettings));
	//	if (verbose)
	//	{
	//		System.out.println(AidaUtil.printResultsOfFit(fitResult));
	//	}
	//	return fitResult;
	//}


	/**
	 *  Fit the IBaseHistogram
	 *
	 *@param  histo        The IBaseHistogram (IHistogram1D, IHistogram2D, etc...)
	 *      to be fitted
	 *@param  fitSettings  The FitSettings to be used
	 *@return              The results of the fit
	 */
	public IFitResult doFit(IBaseHistogram histo, FitSettings fitSettings)
	{
		IFunction func = prepareFit(fitSettings);
		return fitter.fit(histo, func);
	}


	/**
	 *  Fit the H1D
	 *
	 *@param  h1d          The H1D to be fitted
	 *@param  fitSettings  The FitSettings to be used
	 *@return              The results of the fit
	 */
	public IFitResult doFit(H1D h1d, FitSettings fitSettings)
	{
		IFunction func = prepareFit(fitSettings);
		IHistogram1D histo = h1d.get();
		return fitter.fit(histo, func);
	}


	/**
	 *  Fit the IFitData
	 *
	 *@param  fitData      The IFitData to be fitted
	 *@param  fitSettings  The FitSettings to be used
	 *@return              The results of the fit
	 */
	public IFitResult doFit(IFitData fitData, FitSettings fitSettings)
	{
		IFunction func = prepareFit(fitSettings);
		return fitter.fit(fitData, func);
	}
}

